use std::path::Path;

/// 检测文件的编程语言
pub fn detect_language_from_path(file_path: &str) -> Option<String> {
    let path = Path::new(file_path);
    
    // 首先检查文件名
    if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
        match file_name {
            "Cargo.toml" | "Cargo.lock" => return Some("toml".to_string()),
            "package.json" | "tsconfig.json" => return Some("json".to_string()),
            "Dockerfile" => return Some("dockerfile".to_string()),
            "Makefile" => return Some("makefile".to_string()),
            _ => {}
        }
    }
    
    // 然后检查扩展名
    if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) {
        Some(detect_language_from_extension(extension))
    } else {
        None
    }
}

/// 根据文件扩展名检测编程语言
pub fn detect_language_from_extension(extension: &str) -> String {
    match extension.to_lowercase().as_str() {
        // Rust
        "rs" => "rust".to_string(),
        
        // Python
        "py" | "pyw" | "pyi" => "python".to_string(),
        
        // JavaScript/TypeScript
        "js" | "mjs" | "cjs" => "javascript".to_string(),
        "ts" | "mts" | "cts" => "typescript".to_string(),
        "tsx" => "typescriptreact".to_string(),
        "jsx" => "javascriptreact".to_string(),
        
        // Java
        "java" => "java".to_string(),
        
        // C/C++
        "c" => "c".to_string(),
        "cpp" | "cc" | "cxx" | "c++" => "cpp".to_string(),
        "h" | "hpp" | "hxx" | "h++" => "c".to_string(),
        
        // C#
        "cs" => "csharp".to_string(),
        
        // Go
        "go" => "go".to_string(),
        
        // PHP
        "php" | "phtml" => "php".to_string(),
        
        // Ruby
        "rb" | "rbw" => "ruby".to_string(),
        
        // Swift
        "swift" => "swift".to_string(),
        
        // Kotlin
        "kt" | "kts" => "kotlin".to_string(),
        
        // Dart
        "dart" => "dart".to_string(),
        
        // Scala
        "scala" | "sc" => "scala".to_string(),
        
        // Clojure
        "clj" | "cljs" | "cljc" => "clojure".to_string(),
        
        // Haskell
        "hs" | "lhs" => "haskell".to_string(),
        
        // Erlang/Elixir
        "erl" | "hrl" => "erlang".to_string(),
        "ex" | "exs" => "elixir".to_string(),
        
        // Web technologies
        "html" | "htm" => "html".to_string(),
        "css" => "css".to_string(),
        "scss" | "sass" => "scss".to_string(),
        "less" => "less".to_string(),
        "vue" => "vue".to_string(),
        "svelte" => "svelte".to_string(),
        
        // Data formats
        "json" => "json".to_string(),
        "xml" => "xml".to_string(),
        "yaml" | "yml" => "yaml".to_string(),
        "toml" => "toml".to_string(),
        "ini" => "ini".to_string(),
        "csv" => "csv".to_string(),
        
        // Documentation
        "md" | "markdown" => "markdown".to_string(),
        "rst" => "restructuredtext".to_string(),
        "tex" => "latex".to_string(),
        
        // Shell scripts
        "sh" | "bash" | "zsh" | "fish" => "shellscript".to_string(),
        "ps1" => "powershell".to_string(),
        "bat" | "cmd" => "bat".to_string(),
        
        // Database
        "sql" => "sql".to_string(),
        
        // Configuration
        "conf" | "config" => "properties".to_string(),
        "env" => "properties".to_string(),
        
        // Docker
        "dockerfile" => "dockerfile".to_string(),
        
        // 默认
        _ => "plaintext".to_string(),
    }
}

/// 检查文件是否为源代码文件
pub fn is_source_file(file_path: &str) -> bool {
    if let Some(language) = detect_language_from_path(file_path) {
        // 只识别真正的编程语言源代码文件
        matches!(language.as_str(),
            "rust" | "python" | "javascript" | "typescript" | "typescriptreact" | "javascriptreact" |
            "java" | "c" | "cpp" | "csharp" | "go" | "php" | "ruby" | "swift" | "kotlin" |
            "dart" | "scala" | "clojure" | "haskell" | "erlang" | "elixir" | "shellscript" |
            "powershell" | "bat" | "sql"
        )
    } else {
        false
    }
}

/// 检查文件是否应该被忽略
pub fn should_ignore_file(file_path: &str) -> bool {
    let path = Path::new(file_path);
    
    // 检查文件名
    if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
        if file_name.starts_with('.') {
            return true;
        }
        
        match file_name {
            "node_modules" | "target" | "__pycache__" | ".git" | ".svn" | ".hg" |
            "build" | "dist" | "out" | "bin" | "obj" | ".vscode" | ".idea" |
            "coverage" | ".nyc_output" | ".pytest_cache" | ".tox" => return true,
            _ => {}
        }
    }
    
    // 检查扩展名
    if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) {
        match extension.to_lowercase().as_str() {
            "exe" | "dll" | "so" | "dylib" | "a" | "lib" | "o" | "obj" |
            "bin" | "class" | "jar" | "war" | "ear" | "pyc" | "pyo" |
            "lock" | "log" | "tmp" | "temp" | "cache" | "bak" | "swp" |
            "DS_Store" => return true,
            _ => {}
        }
    }
    
    false
}

/// 格式化文件大小
pub fn format_file_size(size: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    let mut size = size as f64;
    let mut unit_index = 0;
    
    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
        size /= 1024.0;
        unit_index += 1;
    }
    
    if unit_index == 0 {
        format!("{} {}", size as u64, UNITS[unit_index])
    } else {
        format!("{:.1} {}", size, UNITS[unit_index])
    }
}

/// 格式化时间戳
pub fn format_timestamp(timestamp: u64) -> String {
    let datetime = chrono::DateTime::from_timestamp(timestamp as i64, 0)
        .unwrap_or_else(|| chrono::Utc::now());
    
    datetime.format("%Y-%m-%d %H:%M:%S").to_string()
}

/// 验证文件路径
pub fn validate_file_path(path: &str) -> Result<(), String> {
    if path.is_empty() {
        return Err("文件路径不能为空".to_string());
    }
    
    let path_obj = Path::new(path);
    
    // 检查路径是否包含非法字符
    if path.contains('\0') {
        return Err("文件路径包含非法字符".to_string());
    }
    
    // 检查路径长度
    if path.len() > 260 {
        return Err("文件路径过长".to_string());
    }
    
    // 检查是否为绝对路径或相对路径
    if path_obj.is_absolute() {
        // 绝对路径检查
        if !path_obj.exists() {
            return Err("文件路径不存在".to_string());
        }
    }
    
    Ok(())
}

/// 规范化文件路径
pub fn normalize_path(path: &str) -> String {
    let path_obj = Path::new(path);
    
    // 转换为规范路径
    if let Ok(canonical) = path_obj.canonicalize() {
        canonical.to_string_lossy().to_string()
    } else {
        // 如果无法规范化，至少清理路径分隔符
        path.replace('\\', "/")
    }
}

/// 获取相对路径
pub fn get_relative_path(base: &str, target: &str) -> Option<String> {
    let base_path = Path::new(base);
    let target_path = Path::new(target);
    
    if let Ok(relative) = target_path.strip_prefix(base_path) {
        Some(relative.to_string_lossy().to_string())
    } else {
        None
    }
}

/// 检查路径是否在指定目录下
pub fn is_path_under_directory(path: &str, directory: &str) -> bool {
    let path_obj = Path::new(path);
    let dir_obj = Path::new(directory);
    
    path_obj.starts_with(dir_obj)
}

/// 生成唯一的文件名
pub fn generate_unique_filename(base_name: &str, extension: &str) -> String {
    let timestamp = chrono::Utc::now().timestamp();
    let uuid = uuid::Uuid::new_v4().to_string()[..8].to_string();
    
    if extension.is_empty() {
        format!("{}_{}{}", base_name, timestamp, uuid)
    } else {
        format!("{}_{}{}.{}", base_name, timestamp, uuid, extension)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_detect_language_from_extension() {
        assert_eq!(detect_language_from_extension("rs"), "rust");
        assert_eq!(detect_language_from_extension("py"), "python");
        assert_eq!(detect_language_from_extension("js"), "javascript");
        assert_eq!(detect_language_from_extension("ts"), "typescript");
        assert_eq!(detect_language_from_extension("unknown"), "plaintext");
    }
    
    #[test]
    fn test_format_file_size() {
        assert_eq!(format_file_size(512), "512 B");
        assert_eq!(format_file_size(1024), "1.0 KB");
        assert_eq!(format_file_size(1536), "1.5 KB");
        assert_eq!(format_file_size(1048576), "1.0 MB");
    }
    
    #[test]
    fn test_should_ignore_file() {
        assert!(should_ignore_file("node_modules"));
        assert!(should_ignore_file("target"));
        assert!(should_ignore_file(".git"));
        assert!(should_ignore_file("file.exe"));
        assert!(!should_ignore_file("main.rs"));
        assert!(!should_ignore_file("README.md"));
    }
}
